package com.own.business.pay.module.wechat.util;

import com.own.business.pay.common.exception.PayException;
import com.own.business.pay.module.wechat.property.WechatPayProperty;
import lombok.SneakyThrows;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
import java.util.UUID;

/**
 * WechatPaySignatureUtil
 *
 * @author chenxueli
 * @date 2023-08-18 09:03:00
 */
public class WechatPaySignatureUtil {

    private static final String SCHEMA = "WECHATPAY2-SHA256-RSA2048";

    /**
     * 获取签名
     *
     * @param method   请求方式
     * @param uri      请求地址（全路径地址）
     * @param body     请求体
     * @param mchId    商户号
     * @param serialNo 证书序列号
     * @return 签名
     */
    public static String authorization(
            String method,
            String uri,
            String body,
            String mchId,
            String serialNo
    ) {
        try {
            var url = new URI(uri).toURL();
            var nonce = UUID.randomUUID().toString().replace("-", "");
            var timestamp = System.currentTimeMillis() / 1000;
            var message = buildMessage(method, url.getFile(), timestamp, nonce, body);
            var text = encrypt(message, WechatPayProperty.PRIVATE_KEY);
            // 拼接信息
            return SCHEMA + " " +
                    "mchid=\"" + mchId + "\"," +
                    "nonce_str=\"" + nonce + "\"," +
                    "timestamp=\"" + timestamp + "\"," +
                    "serial_no=\"" + serialNo + "\"," +
                    "signature=\"" + text + "\"";
        } catch (Exception e) {
            throw new PayException("微信支付签名失败");
        }
    }

    /**
     * 构建消息
     *
     * @param method    请求方式
     * @param api       请求地址
     * @param timestamp 时间戳
     * @param nonceStr  随机串
     * @param body      请求体
     * @return 消息
     */
    private static String buildMessage(String method, String api, long timestamp, String nonceStr, String body) {
        return method + "\n" + api + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
    }

    /**
     * 加密
     *
     * @param content    内容
     * @param privateKey 私钥
     * @return 加密后的内容
     */
    @SneakyThrows
    public static String encrypt(String content, PrivateKey privateKey) {
        var signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(content.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signature.sign());
    }

}
